package com.abcgroup.hyppo.loader;

import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.Query;

import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;

/**
 * Uses URLClassLoader. Check URLClassLoader comments how to specify paths. 
 */
public class URLFileLoader implements IHibernateLoader {

    List<JarFile> vaults;

    List<String> configurations;

    URLClassLoader classLoader;

    String configurationMask = "\\w+.cfg.xml";

    AnnotationConfiguration hibernateConfiguration;

    public void setConfigurationMask(String configurationMask) {
        this.configurationMask = configurationMask;
    }

    protected void traceJarFile(JarFile file) {
        Enumeration<JarEntry> en = file.entries();
        while (en.hasMoreElements()) {
            JarEntry entry = en.nextElement();
            if (entry.getName().matches(configurationMask)) {
                configurations.add("jar:file:///" + file.getName() + "!/" + entry.getName());
            }
        }
    }

    /**
     * Accepts list of jar files which should contains .class + hibernate configuration files.
     * @param fileNames
     * @throws FileNotFoundException
     */
    public void init(URL[] fileNames, ClassLoader parent) throws FileNotFoundException {
        vaults = new LinkedList<JarFile>();
        configurations = new LinkedList<String>();

        for (URL fileName : fileNames) {
            try {
                vaults.add(new JarFile(fileName.getFile()));
            } catch (IOException e) {
                throw new FileNotFoundException(fileName.toString());
            }
        }

        for (JarFile vault : vaults) {
            traceJarFile(vault);
        }

        classLoader = new URLClassLoader(fileNames, parent);
    }

    public ClassLoader initClassLoader() {
        return classLoader;
    }

    public List<String> getAvailableConfigs() {
        return configurations;
    }

    public Configuration getHibernateConfiguration() {
        return hibernateConfiguration;
    }

    public void configureHibernate(List<String> confs) {
        AnnotationConfiguration conf = new AnnotationConfiguration();
        for (String s : confs) {
            try {
                conf.configure(new URL(s));
            } catch (MalformedURLException e) {
                System.err.println("FUCK " + s);
            }
        }
        hibernateConfiguration = conf;
    }

    public IHibernateLoader setProperty(String n, String v) {
        if (hibernateConfiguration == null) {
            throw new IllegalStateException("Hibernate Loader Did not configured.");
        }
        hibernateConfiguration.setProperty(n, v);
        return this;
    }

    public IHibernateLoader setProperties(Properties props) {
        if (hibernateConfiguration == null) {
            throw new IllegalStateException("Hibernate Loader Did not configured.");
        }
        hibernateConfiguration.setProperties(props);
        return this;
    }

    public Set<String> getAllNamedQueries() {
        if (hibernateConfiguration == null) {
            throw new IllegalStateException("Hibernate Loader Did not configured.");
        }

        return hibernateConfiguration.getNamedQueries().keySet();
    }

    public NamedQueryDefinition getQueryDefinition(String name) {
        return (NamedQueryDefinition) hibernateConfiguration.getNamedQueries().get(name);
    }


}
